#include "table.h"

// for 遍历哈希聚集序列
#define in_hashAccList(tableHeader, currentPair, firstIndex) \
currentPair = tableHeader + firstIndex; \
firstIndex <= TABLE_MAX_INDEX && currentPair->code; \
currentPair++, firstIndex++

// 当前键值对的键是否与给定的键相同
#define isKey(kvPair, givenKey) \
(kvPair->key && strcmp(kvPair->key, givenKey) == 0)

// table长度是否计算过
#define len_inited(tableHeader) \
((tableHeader)->key && *(char*)(tableHeader)->key == 'n' && !*((char*)(tableHeader)->key + 1))

// 计算整数幂的函数
static inline unsigned long long ipow(unsigned long long base, unsigned exp) {
    long long result = 1;
    
    while (exp > 0) {
        if (exp & 1) result *= base;
        base *= base;
        exp >>= 1;
    }
    return result;
}


int hash(const void* bytes, size_t byteCount) {
	int counter = 0;
	unsigned long long int sum = 0;
	
	for (byte *currentByte = (byte*)bytes; counter < byteCount; currentByte++, counter++)
		sum += (unsigned int)(*currentByte) * ipow(TABLE_HASH_BASE, byteCount-counter-1);
	
	return 1 + sum % TABLE_MAX_LEN;
}


int tb_find(table tb, const char* key) {
	if (!key) return -1; // 错误：空指针

	int pos = hash(key, strlen(key));
	
	for (kvp* in_hashAccList(tb, pair, pos))
		if (isKey(pair, key))
			return pos;
	
	return -1; // 错误：没有这个键
}


void* tb_get(table tb, const char* key) {
	if (!key) return NULL; // 错误：空指针
	
	int pos = hash(key, strlen(key));
	
	for (kvp* in_hashAccList(tb, pair, pos))
		if (isKey(pair, key))
			return pair->val; // 返回指向值的指针
	
	return NULL; // 错误：没有这个键
}


int tb_set(table tb, const char* key, const void* val) {
	if (!key || !val) return 1; // 错误：空指针
	
	const int hashCode = hash(key, strlen(key));
	int pos = hashCode, isNew = 1;
	kvp *pair;
	
	for (in_hashAccList(tb, pair, pos)) {
		if (pair->code < 0) {
			break; // 允许复用已经解绑的槽
		} else if (isKey(pair, key)) {
			isNew = 0; // 更新指向而不是新增
			break;
		}
	} // 跳过聚集区

	if (pos > TABLE_MAX_INDEX)
		return 1; // 错误：没有多余空位

	pair->code = hashCode;
	pair->key = (char*)key;
	pair->val = (void*)val;
	
	if (isNew && len_inited(tb))
		tb->code++; // table长度+1
	return 0; // 成功设置
}


int tb_pull(table tb, const char* key, char* out, size_t size) {
	if (!out || !size) return 0;

	int idx = tb_find(tb, key);
	if (idx == -1 || strlen(tb[idx].val) >= size)
		return 0; // 错误：没有这个键或空间不足
	
	strcpy(out, tb[idx].val);
	return 1;
}


int tb_push(table tb, const char* key, const char* val) {
	if (!val) return 1;

	int idx = tb_find(tb, key);
	if (idx == -1) return 1;

	strcpy(tb[idx].val, val);
	return 0;
}


int kvp_unset(kvp* pair) {
	if (!pair) return 1;
	pair->key = NULL;
	pair->val = NULL;
	pair->code *= -1;
	return 0;
}


int tb_del(table tb, const char* key) {
	if (!key) return 1; // 错误：空指针
	
	int pos = hash(key, strlen(key));
	
	for (kvp* in_hashAccList(tb, pair, pos))
		if (isKey(pair, key)) {
			pair->key = NULL;
			pair->val = NULL;
			pair->code *= -1;
			
			if (len_inited(tb))
				tb->code--; // table长度-1
			return 0;
		}
	
	return 1;
}


int tb_pop(table tb, const char* key, kvp* out) {
	if (!key || !out) return 1; // 错误：空指针
	
	int pos = hash(key,strlen(key));
	
	for (kvp* in_hashAccList(tb, pair, pos))
		if (isKey(pair, key)) {
			*out = *pair; // 保存副本
			
			pair->key = NULL;
			pair->val = NULL;
			pair->code *= -1;
			
			if (len_inited(tb))
				tb->code--; // table长度-1
			return 0;
		}
	
	return 1;
}


int tb_len(table tb) {
	if (len_inited(tb)) // 如果长度已经计算过
		return tb->code;
	
	int length = 0;
	kvp *p = tb + 1, *last = tb + TABLE_MAX_LEN; // 第一个槽和最后一个槽
	while (p <= last) {
		if (p->code > 0) length++;
		p++;
	}

	tb->key = tb->val = "n";
	tb->code = length;
	return length;
}


kvp *next(table tb, const kvp* pair) {
	kvp *last = tb + TABLE_MAX_LEN;
	
	for (pair++; pair <= last; pair++)
		if (pair->code > 0)
			return (kvp*)pair;
	
	return NULL;
}

#undef in_hashAccList
#undef isKey
#undef len_inited
